home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
BG_SRC.ZIP
/
BG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-24
|
18KB
|
588 lines
/*
*
* B G . C
* O.F.Ransen: 21st June 1991
* This version: 27th April 1994
*
*
*/
#include "comp.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include "bg.h"
#include "mousy.h"
FILE* Rec_File = NULL ;
boolean Debugging = FALSE ; /* If writing moves to a file */
boolean Genetics = FALSE ; /* If doing Darwininian selection */
boolean F10_Hit = FALSE ; /* Recieves F10 key from anywhere */
extern Stats_t Statistics [N_PLAYERS] ;
extern int Target_Score ;
/*************************************************************************/
static void Open_Record_File (ushort n) ;
static void Swap_Players (Player_t* Pa, Player_t* Pb) ;
static void Command_Line_Read (int argc, char* argv[]) ;
static void Update_Score (Player_t Player, int Points) ;
static boolean Game_Over (Player_t Human) ;
/*************************************************************************/
void main (int argc, char* argv[])
{
boolean Running ;
Speed_t Speed ;
short Opponent ;
Player_t Human ; /* WHITE_PLAYER or BLACK_PLAYER */
Check_Mouse () ;
Command_Line_Read (argc,argv) ;
Set_Ctl_C_Handler () ;
Decode_And_Show_Titles () ;
Print_Message (HAKTOC_MSG) ;
(void)Get_Key() ;
Init_Stats () ;
Init_Rannum_Gen () ;
Init_Graphics () ;
Start_Up_Mouse () ;
Randomise () ;
if (Genetics) {
Genetic_Selection () ;
} else {
Opponent = SERGIO ;
Human = BLACK_PLAYER ;
Speed = SLOW_SPEED ;
Running = First_Interaction (&Speed,&Human,&Opponent) ;
while (Running) {
boolean Playing ;
Init_Stats () ;
Playing = TRUE ;
while (Playing) {
Print_Players (Opponent,Human) ;
Playing = Play_The_Game (Speed,Human,Opponent) ;
}
Running = Top_Level_Interact (&Speed,&Human,&Opponent) ;
}
}
Go_Text_Mode () ;
Show_Titles () ;
}
/*************************************************************************/
boolean Play_The_Game (Speed_t Speed, Player_t Human, short O_Index)
/*
PURPOSE: To play a single game of backgammon, returning TRUE while
the target score has not been reached. We return FALSE when
the target score has been reached or when the user hits F10.
NOTES: 2) If Human!=NULL_PLAYER then the Human is either red or
white and wants to play against the computer.
*/
{
Layout_t Curr_Lay[2] ; /* The current layouts */
Transit_t Transit[2] ; /* The new layouts and how we got there */
Player_t Opponent,Player,Starter ;
boolean First_Loop, /* Dice already thrown, just move */
Finished, /* Game over */
Can_Move, /* Move possible with these dice */
Doubled, /* Current player doubled stakes */
Rejected ; /* Current opponent rejected stakes */
extern Player_t Double_Possessor ;
extern int Double_Value ;
extern int N_Moves ;
Dice_t Dice ;
char User_Char ;
short Points ;
if (Debugging) {
Open_Record_File (0) ;
}
#if DRODBAR
Test_Move () ;
#endif
N_Moves = 0 ; // Helps to decide when to double
Double_Value = 1 ; /* No double yet */
Double_Possessor = NULL_PLAYER ;
Initial_Board (Curr_Lay) ;
Draw_Board_Full (Curr_Lay) ;
if (!Genetics) {
Show_Opponents_Face (Curr_Lay,Human,O_Index) ;
Draw_Eyes (2,O_Index) ;
}
Select_Starter (&Starter,&Dice) ;
if (F10_Hit) {
F10_Hit = FALSE ;
return (F10_KEY) ;
}
Player = Starter ;
Opponent = OPPONENT(Starter) ;
First_Loop = TRUE ; /* So we don't throw the dice again */
Finished = FALSE ;
User_Char = 0 ; /* Not Escape yet */
Print_Message (HELP_MSG) ;
do {
if (!First_Loop) {
/* Have to throw the dice */
if (Move_Possible (Curr_Lay[Player],Curr_Lay[Opponent])) {
/* It is worth throwing the dice */
Dice = Throw_Dice (Player,Opponent,Human,&Doubled,&Rejected,Curr_Lay) ;
if (F10_Hit) {
F10_Hit = FALSE ;
return (FALSE) ;
}
if (Doubled && Rejected) {
/* Opponent rejected the double, so Player wins */
Update_Score (Player,1) ;
Show_Winner (Player,Human,1) ;
Finished = TRUE ;
Can_Move = FALSE ;
/*
* See if we have finished the whole set.
*/
if (Game_Over (Human)) {
return (FALSE) ;
} else {
User_Char = (char)Key_And_Delay (3) ; /* Wait a bit */
return (User_Char != F10_KEY) ;
}
} else {
Draw_Dice_Pair (&Dice,Player) ;
if (!Genetics) {
Draw_Eyes (Dice.N_Vals,O_Index) ;
}
Can_Move = TRUE ;
}
} else {
/* Move is not possible */
if (Player == WHITE_PLAYER) {
Print_Message (W_NOGO_MSG) ;
} else {
Print_Message (B_NOGO_MSG) ;
}
Seconds_Delay (2) ;
Swap_Players (&Player,&Opponent) ;
Finished = FALSE ;
Can_Move = FALSE ;
}
} else {
/* Dice already thrown for us */
Can_Move = TRUE ;
First_Loop = FALSE ;
}
if (Can_Move) {
Draw_Stats () ;
if (Player == Human) {
User_Char = User_Selects_Move (&Dice,
Curr_Lay [Player], Curr_Lay [Opponent],
&Transit [Player], &Transit [Opponent],
Player) ;
if (User_Char == F10_KEY) {
F10_Hit = FALSE ;
return (FALSE) ;
}
} else {
if (Human != NULL_PLAYER) {
Seconds_Delay (2) ; /* So man can sees computers dice */
}
Select_Best_Move (&Dice,
Curr_Lay [Player], Curr_Lay [Opponent],
&Transit [Player], &Transit [Opponent],
Player,Bestest) ;
}
Copy_Layout (Curr_Lay [Player], Transit[Player].Layout) ;
Copy_Layout (Curr_Lay [Opponent],Transit[Opponent].Layout) ;
if (!Genetics) {
Show_Opponents_Face (Curr_Lay,Human,O_Index) ;
}
if (Player != Human) {
/* Show the human how the computer moved */
User_Char = Show_Transits_And_Kb_Look (&Transit [Player],
&Transit [Opponent],
Player,Speed) ;
Draw_Board_Quick (Curr_Lay[BLACK_PLAYER],Curr_Lay[WHITE_PLAYER]) ;
}
if (Debugging) {
Record_Move (Player,&Dice,Curr_Lay[BLACK_PLAYER],Curr_Lay[WHITE_PLAYER]) ;
}
Finished = (User_Char == F10_KEY) ;
Points = Won (Curr_Lay[Player],Curr_Lay[Opponent]) ;
if (Points > NO_WIN) {
Update_Score (Player,Points) ;
Show_Winner (Player,Human,Points) ;
Finished = TRUE ;
/*
* See if we have finished the whole set.
*/
if (Game_Over (Human)) {
return (FALSE) ;
} else {
User_Char = (char)Key_And_Delay (2) ;
return (User_Char != F10_KEY) ;
}
} else {
Swap_Players (&Player,&Opponent) ;
}
}
N_Moves++ ;
} while (!Finished) ;
if (Debugging) {
fclose (Rec_File) ;
Rec_File = NULL ;
}
return (User_Char != F10_KEY) ;
}
/*************************************************************************/
void Select_Starter (Player_t* Player, Dice_t* Dice)
/*
PURPOSE: To select who will start the game, with graphics. We return who
starts the game in Player, and the dice with which he starts in Dice.
*/
{
int Black_Score,White_Score,Rand_Rolls,r ;
extern Throw_t Throw ;
Dice_t Temp_Dice ;
if (Throw == MANUAL_THROW) {
do {
Temp_Dice = Human_Throws_Dice (BLACK_PLAYER,WHITE_PLAYER) ;
if (F10_Hit) {
return ;
}
} while (Temp_Dice.Values[0] == Temp_Dice.Values[1]) ;
Copy_Dice (Dice,&Temp_Dice) ;
Black_Score = Temp_Dice.Values[BLACK_PLAYER] ;
White_Score = Temp_Dice.Values[WHITE_PLAYER] ;
} else {
do {
if (Genetics) {
Rand_Rolls = 1 ;
} else {
Rand_Rolls = Int_Rand_Range (MIN_ROLLS,MAX_ROLLS) ;
}
for (r = 0 ; r < Rand_Rolls ; r++) {
Black_Score = Int_Rand_Range (1,6) ;
White_Score = Int_Rand_Range (1,6) ;
Draw_Die (Black_Score,1,BLACK_PLAYER) ;
Draw_Die (White_Score,2,WHITE_PLAYER) ;
}
Seconds_Delay (3) ;
} while (Black_Score == White_Score) ;
Dice->N_Vals = 2 ;
Dice->Values[0] = (char)Black_Score ;
Dice->Values[1] = (char)White_Score ;
}
if (Black_Score > White_Score) {
(*Player) = BLACK_PLAYER ;
} else {
(*Player) = WHITE_PLAYER ;
}
/* Update the dice statistics of the winning player */
Statistics [(*Player)].N_Throws++ ;
Statistics [(*Player)].Total += (Black_Score + White_Score) ;
}
/*************************************************************************/
void Seconds_Delay (short seconds)
/* PURPOSE: Guess. */
{
time_t Then, Now ;
if (Genetics) {
return ; // Go as fast as you can!
}
(void)time (&Then) ;
do {
(void)time (&Now) ;
} while ((Now - Then) < seconds) ;
}
/***************************************************************************/
void Record_Move (Player_t Player, Dice_t* Dice,
Layout_t Black, Layout_t White)
/*
PURPOSE: To file the move in the global Rec_File.
*/
{
short d ;
if (Rec_File == NULL) {
Error_Exit ("Writing to NULL Rec_File") ;
}
fprintf (Rec_File,"\nDice_t = ") ;
fprintf (Rec_File,"{%1d,{",Dice->N_Vals) ;
for (d=0 ; d < MAX_MOVES-1 ; d++) {
fprintf (Rec_File,"%1d,",Dice->Values[d]) ;
}
fprintf (Rec_File,"%1d}} ; ",Dice->Values[d]) ;
if (Player == BLACK_PLAYER) {
fprintf (Rec_File,"/* BLACK */") ;
} else {
fprintf (Rec_File,"/* WHITE */") ;
}
Print_Layouts (Black,White) ;
fprintf (Rec_File,"\n") ;
}
/***************************************************************************/
void Print_Layouts (Layout_t Black, Layout_t White)
/*
PURPOSE: A debugging printout of the board into the Rec_File
*/
{
Print_Layout (White,WHITE_PLAYER) ;
Print_Layout (Black,BLACK_PLAYER) ;
}
/*************************************************************************/
void Print_Layout (Layout_t Layout, Player_t Player)
/*
PURPOSE: To print the layout in an easily machine and human readable form.
*/
{
ushort p,o,r ;
if (Player == BLACK_PLAYER) {
fprintf (Rec_File,"\n\nLayout_t Black_Lay = {") ;
} else {
fprintf (Rec_File,"\n\nLayout_t White_Lay = {") ;
}
fprintf (Rec_File,"%2d, /* BAR_I */ ",Layout[BAR_I]) ;
for (r = 0 ; r < 4 ; r++) {
o = r*6 ;
fprintf (Rec_File,"\n ") ;
for (p = 1 ; p <= 6 ; p++) {
fprintf (Rec_File,"%2d,",Layout[o+p]) ;
}
}
fprintf (Rec_File,"\n %2d}; /* HOME_I*/ ",
Layout[HOME_I]) ;
}
/*************************************************************************/
#if DRODBAR
Dice_t Test_Dice = {4,{3,3,3,3}} ; /* New layouts = */
Layout_t White_Lay = { 0, /* BAR_I */
0, 0, 0, 3, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 3,
7}; /* HOME_I*/
Layout_t Black_Lay = { 0, /* BAR_I */
0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 3,
0, 0, 0, 0, 0, 0,
5, 2, 0, 0, 0, 0,
4}; /* HOME_I*/
void Test_Move (void)
/*
PURPOSE: To see how and why the computer moves as he did...
*/
{
Player_t Player,Opponent ;
Layout_t Curr_Lay[2] ; /* The current layouts */
Transit_t Transit[2] ; /* The new layouts and how we got there */
Copy_Layout (Curr_Lay[BLACK_PLAYER],Black_Lay) ;
Copy_Layout (Curr_Lay[WHITE_PLAYER],White_Lay) ;
Player = WHITE_PLAYER ;
Opponent = BLACK_PLAYER ;
Draw_Board_Full (Curr_Lay) ;
Draw_Dice_Pair (&Test_Dice,Player) ;
(void)User_Selects_Move (&Test_Dice,
Curr_Lay [Player], Curr_Lay [Opponent],
&Transit [Player], &Transit [Opponent],
Player) ;
Show_Transits_And_Kb_Look (&Transit [Player],
&Transit [Opponent],
Player,PAUSING) ;
Draw_Board_Quick (Curr_Lay[BLACK_PLAYER],Curr_Lay[WHITE_PLAYER]) ;
Error_Exit ("") ;
}
/*************************************************************************/
#endif
/*************************************************************************/
static void Open_Record_File (ushort n)
/*
PURPOSE: To open a file to record the moves of the nth game. The name
is based on the number.
*/
{
char Num_Str[8], Name[16] ;
sprintf (Num_Str,"%d",n) ;
(void)strcpy (Name,"BG") ;
(void)strcat (Name,Num_Str) ;
(void)strcat (Name,".REC") ;
Rec_File = fopen (Name,"w") ; /* Write Text File */
if (Rec_File == NULL) {
Error_Exit ("Cannot open record file") ;
}
fprintf (Rec_File,"\n/* SEQUENCE OF MOVES, %s */\n",VER_STR) ;
}
/*************************************************************************/
void Swap_Players (Player_t* Pa, Player_t* Pb)
/* Swap the two players */
{
Player_t Temp ;
Temp = (*Pa) ;
(*Pa) = (*Pb) ;
(*Pb) = Temp ;
}
/*************************************************************************/
/* The options type, a command line option and the address of the
boolean it affects */
#define N_OPTIONS 4
typedef struct {
char Name[20] ;
boolean* Adr ;
} Opt_t ;
extern boolean Force_BW ;
static Opt_t Options [N_OPTIONS] = {
{"debug", &Debugging}, /* Writes all moves to a file */
{"genetics",&Genetics}, /* All-Computer tournament, no interaction */
{"mono", &Force_BW}} ; /* Forces black and white display */
static void Command_Line_Read (int argc, char* argv[])
/*
PURPOSE: To see if the user has typed any special command line
options, and to set the options accordingly.
*/
{
short a,o ;
for (a = 0 ; a < argc ; a++) {
for (o = 0 ; o < N_OPTIONS ; o++) {
if (strcmpi (argv[a],Options[o].Name) == SAME_STRING) {
(*Options[o].Adr) = TRUE ;
}
}
}
}
/*************************************************************************/
static void Update_Score (Player_t Player, int Points)
/*
PURPOSE: To update the stats for the player, display them, and set
No_Cube to the correct value.
*/
{
extern int Double_Value ;
extern int Target_Score ;
extern boolean No_Cube ;
Statistics[Player].Games_Won+= (Double_Value*Points) ;
Draw_Stats () ;
if (!No_Cube) {
/* Either before or after freeze */
if (Statistics[BLACK_PLAYER].Games_Won != Statistics[WHITE_PLAYER].Games_Won) {
if (Statistics[Player].Games_Won == (Target_Score-1)) {
Print_Message (NO_CUBE_MSG) ;
No_Cube = TRUE ;
} else {
No_Cube = FALSE ;
}
} else {
No_Cube = FALSE ;
}
} else {
/* It has been TRUE, it last for one game only */
No_Cube = FALSE ;
}
}
/*************************************************************************/
static boolean Game_Over (Player_t Human)
/*
PURPOSE: To return TRUE if the whole set of matches is finished.
If the Human is playing then we write some messages for him too.
*/
{
if (Human != NULL_PLAYER) {
if (Statistics[OPPONENT(Human)].Games_Won >= Target_Score) {
Print_Message (COM_WINS_SET_MSG) ;
Seconds_Delay (2) ;
return (TRUE) ;
} else if (Statistics[Human].Games_Won >= Target_Score) {
Print_Message (YOU_WIN_SET_MSG) ;
Seconds_Delay (2) ;
return (TRUE) ;
} else {
return (FALSE) ;
}
} else {
if (Statistics [BLACK_PLAYER].Games_Won >= Target_Score) {
return (TRUE) ;
} else if (Statistics [WHITE_PLAYER].Games_Won >= Target_Score) {
return (TRUE) ;
} else {
return (FALSE) ;
}
}
}
/*************************************************************************/